package com.chunlin.generic;

import java.lang.reflect.Array;

public class MyAarray<T> {
    // 不能new泛型类型的数组
    //T[] array = new T[10];//是不对的
    //为什么不对,下面来解释一下
    //在编译时，Java的泛型类型参数（例如T）被类型擦除为它的非泛型上界。如果没有指定上界，则默认为Object。
    //编译的时候T的类型被擦除为Object,上面的代码也就变成了Object[] array = new Obejct[10];
    //但是Java数组在运行时需要知道其元素的具体类型，以确保类型安全。创建泛型数组时，由于类型擦除，无法在运行时知道泛型类型T的具体类型
    //所以这样导致了编译不通过
    //因此，直接创建泛型数组是不被允许的，因为编译器无法确保类型安全
    public T[] array;

    public MyAarray() {
        //为什么通过创建 Object 数组并将其强制转换为 T[] 类型可以解决问题?
        //当创建一个 Object 数组时，数组的类型在运行时是 Object[]。这不会触发任何编译时错误，因为 Object 是所有类型的超类
        //通过将 Object[] 强制转换为 T[]，你告诉编译器你知道这样做的风险，并且你会确保类型安全
        //编译时类型擦除：泛型类型 T 被擦除为 Object，但变量 array 的声明类型仍然是 T[]
        //实际数组类型：在运行时创建的数组实际是 Object[]，通过 (T[]) 强制转换将其视为 T[]
        //所以这个Object数组,可以接收子类来进行保存
        //因为保存的是子类,所以可以直接进行返回,而不是保存的是Object类,还要经过类型转换而返回(这个还不被允许)
        this.array = (T[])new Object[10];
    }

    public MyAarray(Class<T> clazz, int size) {
        //类型擦除问题
        //在Java中，泛型是在编译时处理的，称为类型擦除（Type Erasure）
        // 类型擦除机制在编译时会将泛型类型参数（例如T）替换为它们的非泛型上界（通常是Object）
        // 这意味着在运行时无法知道泛型类型的具体信息
        // 因此，直接创建泛型数组（如new T[10]）是不被允许的，因为编译器无法确定数组的实际类型，导致潜在的类型安全问题
        //
        //使用反射创建泛型数组
        //反射是Java提供的一个强大工具，它允许在运行时获取类的类型信息，并动态创建对象和数组
        // 通过使用Array.newInstance方法，可以创建具体类型的数组，并在运行时提供类型安全性
        this.array = (T[]) Array.newInstance(clazz, size);
    }

    public T getPos(int pos) {
        return this.array[pos];
    }

    public void setVal(int pos, T val) {
        this.array[pos] = val;
    }


    //替换后的方法为：将Object[]分配给Integer[]引用，程序报错
    //返回的Object数组里面，可能存放的是任何的数据类型，可能是String，可能是Double
    // 运行的时候，直接转给Integer类型的数组，编译器认为是不安全的。

    //为什么通过反射创建的泛型类型数组,可以进行返回
    //因为反射创建的泛型类型数组,它是有具体的类型的,也是Object的子类,所以可以作为返回值
    //不用担心外部不能接受Object的对象数组,因为这里是确定有具体的类型,只要类型相同,可以自动进行转换的
    public T[] getArray() {
        return this.array;
    }
}
